﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SceneLib;
using Tao.OpenGl;

namespace OpenGL
{
    class Ecosystem
    {
        private SceneModel model;
        private Swarm swarm;
        private int displayList;

        public Ecosystem(SceneModel boidModel, Vector center, float radius)
        {   
            swarm = new Swarm(center, radius);
            model = boidModel;
        }

        public void InitBird()
        {
            displayList = Gl.glGenLists(3);

            Gl.glNewList(displayList, Gl.GL_COMPILE);

            Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_SPECULAR,
                            MathUtils.GetVector3Array(model.Triangles[0].Materials[0].Specular));
            Gl.glMaterialf(Gl.GL_FRONT_AND_BACK, Gl.GL_SHININESS,
                           model.Triangles[0].Materials[0].Shininess);
            Gl.glColor3fv(MathUtils.GetVector3Array(model.Triangles[0].Materials[0].Diffuse));
            SetTextures(model.Triangles[0].Materials[0]);

            Gl.glPushMatrix();
            Gl.glTranslatef(model.Position.x, model.Position.y, model.Position.z);
            Gl.glRotatef(model.Rotation.x, 1.0f, 0.0f, 0.0f);
            Gl.glRotatef(model.Rotation.y, 0.0f, 1.0f, 0.0f);
            Gl.glRotatef(model.Rotation.z, 0.0f, 0.0f, 1.0f);
            Gl.glScalef(model.Scale.x * 0.3f, model.Scale.y * 0.3f, model.Scale.z * 0.3f);

            Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
            Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
            Gl.glEnableClientState(Gl.GL_NORMAL_ARRAY);

            Gl.glNormalPointer(Gl.GL_FLOAT, 0, model.NormalsArray);
            Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, model.VertexArray);
            Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, model.TexArray);

            short[] indexes = model.IndexArray;
            Gl.glDrawElements(Gl.GL_TRIANGLES, indexes.Length,
                              Gl.GL_UNSIGNED_SHORT, indexes);

            Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
            Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
            Gl.glDisableClientState(Gl.GL_NORMAL_ARRAY);

            Gl.glPopMatrix();
            Gl.glEndList();
        }

        public void Move()
        {
            swarm.MoveBoids();
        }

        public void Draw()
        {
            foreach (Boid boid in swarm.Boids)
            {
                Gl.glPushMatrix();

                float alfa, beta, gamma;

                alfa = (float)Math.Acos(-boid.velocity.x / boid.velocity.Magnitude3());
                beta = (float)Math.Acos(-boid.velocity.y / boid.velocity.Magnitude3());
                gamma = (float)Math.Acos(-boid.velocity.z / boid.velocity.Magnitude3());
                
                //Dibuja boid
                Gl.glTranslatef(boid.position.x, boid.position.y, boid.position.z);
                
                Gl.glRotatef(gamma * 360 / (2.0f * (float)Math.PI), 1.0f, 0.0f, 0.0f);
                Gl.glRotatef(gamma * 360 / (2.0f * (float)Math.PI), 0.0f, 1.0f, 0.0f);
                Gl.glRotatef(beta * 360 / (2.0f * (float)Math.PI), 1.0f, 0.0f, 0.0f);
                Gl.glRotatef(beta * 360 / (2.0f * (float)Math.PI), 0.0f, 0.0f, 1.0f);                
                Gl.glRotatef(alfa * 360 / (2.0f * (float)Math.PI), 0.0f, 1.0f, 0.0f);
                Gl.glRotatef(alfa * 360 / (2.0f * (float)Math.PI), 0.0f, 0.0f, 1.0f);

                Gl.glCallList(displayList);

                Gl.glPopMatrix();
            }
        }

        private void SetTextures(SceneMaterial sceneMat)
        {
            if (sceneMat.TextureImage != null)
            {

                Gl.glEnable(Gl.GL_TEXTURE_2D);

                sceneMat.CreatePointer();

                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);

                //Seteo de la textura usada
                Gl.glTexImage2D(Gl.GL_TEXTURE_2D,
                                0,
                                Gl.GL_RGBA,
                                sceneMat.TextureImage.Width,
                                sceneMat.TextureImage.Height,
                                0,
                                Gl.GL_BGR,
                                Gl.GL_UNSIGNED_BYTE,
                                sceneMat.PtrBitmap);
            }
            else
            {
                Gl.glDisable(Gl.GL_TEXTURE_2D);
            }
        }
    }
}
